/**
  ******************************************************************************
  * @author     Chris
  * @since      2024/6/15 17:37
  *
  * @file       hd_motor.c
  * @brief      Motor hardware driver.
  *
  * @note       This file contains the hardware driver for the Motor.
  *
  * @warning    None.
  ******************************************************************************
  * Change Logs:
  *   Date          Author       Notes
  *   2024/6/15     Chris        the first version
  *
  ******************************************************************************
  */


#include "hd_motor.h"


static void Motor_init_(const Motor *this) {
    // AIN1 and AIN2 init
    GPIO_init(this->in1GPIO);
    GPIO_init(this->in2GPIO);
}

static void Motor_start_(const Motor *this) {
    this->vptr->set_speed(this, this->speed);
}

static void Motor_stop_(const Motor *this) {
    this->vptr->set_speed(this, 0);
}

/**
 * @brief   motor speed control
 *
 * @note    -----------------------------------------------
 *          | IN1 | IN2 | PWM | STBY |  O1 |  O2 | Status |
 *          |-----|-----|-----|------|-----|-----|--------|
 *          |  H  |  H  | H/L |  H   |  L  |  L  |  Wait  |
 *          |  L  |  H  |  H  |  H   |  L  |  H  | Invert |
 *          |  L  |  H  |  L  |  H   |  L  |  L  |  Wait  |
 *          |  H  |  L  |  H  |  H   |  H  |  L  |  Run   |
 *          |  H  |  L  |  L  |  H   |  L  |  L  |  Wait  |
 *          |  L  |  L  |  H  |  H   |    OFF    |  Stop  |
 *          | H/L | H/L | H/L |  L   |    OFF    |  STBY  |
 * @param   this  motor instance
 * @param   speed motor speed. [-100, 100]
 * @retval  None
 */
static void Motor_setSpeed_(const Motor *this, const int8_t speed) {
    if (speed >= 0) {
        GPIO_set(this->in1GPIO);
        GPIO_reset(this->in2GPIO);
        TimerOC_setCCR(this->timerPwm->timerOC, this->timerPwm->timerOC->timerCh->channels[0], speed);
    } else {
        GPIO_reset(this->in1GPIO);
        GPIO_set(this->in2GPIO);
        TimerOC_setCCR(this->timerPwm->timerOC, this->timerPwm->timerOC->timerCh->channels[0], -speed);
    }
}

void Motor_constructor(Motor *this, TimerPWM *timerPwm, GPIO *in1GPIO, GPIO *in2GPIO) {
    static struct MotorVtbl vtbl = {
        .init = &Motor_init_,
        .start = &Motor_start_,
        .stop = &Motor_stop_,
        .set_speed = &Motor_setSpeed_,
    };

    this->vptr = &vtbl;

    this->timerPwm = timerPwm;
    this->in1GPIO = in1GPIO;
    this->in2GPIO = in2GPIO;
    this->speed = 0;
}
